home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Pascal Super Library
/
Pascal Super Library (CW International)(1997).bin
/
DELPHI32
/
MATH
/
PI
/
ARCTAN.PAS
next >
Wrap
Pascal/Delphi Source File
|
1996-06-17
|
7KB
|
277 lines
unit arctan;
interface
uses
Forms, SysUtils;
const
// If you want you can set these back to 9, 10 and 1 to see the performance
// with only one digit per array entry.
MaxValue = 99;
LessValue = 100;
MinPlaces = 2;
type
// My initial design called for a base class TArbitraryPrecision that just
// took parameters (data, value, size). But I decided it would be faster if
// everything was in the one class as there would be less parameter passing
// required then. Of course thinking about it later the impact of the
// parameter passing would have been insignificant compared to the times
// taken to do the calculations. So perhaps I should have gone for the
// cleaner design?
TByte = array[1 .. ((MaxInt div sizeof(Byte)) - 1)] of Byte;
PTByte = ^TByte;
TCalculatePi = class
precision: Integer;
vm, vn: PTByte;
private
procedure SetUp(Divisor: Integer);
procedure Add;
procedure Subtract;
procedure Multiply(Multiplier: Integer);
procedure Divide(Divisor: Integer);
procedure WriteSource(FileName: string; Divisor, Iterations: Integer);
procedure ReadSource(FileName: string);
public
constructor Create(SetPrecision: Integer);
destructor Destroy;
procedure ArcTan(Divisor: Integer);
procedure Sum;
end;
implementation
uses pidata;
constructor TCalculatePi.Create(SetPrecision: Integer);
begin
PiDataModule.start_position:= 1;
precision:= SetPrecision;
GetMem(vm, Precision + 1);
GetMem(vn, Precision + 1);
end;
destructor TCalculatePi.Destroy;
begin
FreeMem(vn, precision + 1);
FreeMem(vm, precision + 1);
end;
procedure TCalculatePi.SetUp(Divisor: Integer);
var
index: Integer;
begin
PiDataModule.start_position:= 1;
// Calculate vn as 1/K
fillchar(vn^, precision, 0);
vn^[1]:= 1;
Divide(Divisor);
// And copy it back into vm
Move(vn^, vm^, precision);
end;
// Note: The checks in the while loops in the next three functions on the
// index > 0 is probably superflous
procedure TCalculatePi.Add;
var
index, carry: Integer;
begin
carry:= 0;
index:= precision;
while (index > 0) and
((index >= PiDataModule.start_position) or (carry <> 0)) do
begin
vm^[index]:= vm^[index] + vn^[index] + carry;
if vm^[index] > MaxValue then
begin
carry:= 1;
vm^[index]:= vm^[index] - LessValue;
end
else
carry:= 0;
Dec(index);
end;
end;
procedure TCalculatePi.Subtract;
var
index, carry, temp: Integer;
begin
carry:= 0;
index:= precision;
while (index > 0) and
((index >= PiDataModule.start_position) or (carry <> 0)) do
begin
temp:= vm^[index] - vn^[index] - carry;
if temp < 0 then
begin
carry:= 1;
vm^[index]:= temp + LessValue;
end
else
begin
carry:= 0;
vm^[index]:= temp;
end;
Dec(index);
end;
end;
procedure TCalculatePi.Multiply(Multiplier: Integer);
var
index, carry, temp: Integer;
begin
carry:= 0;
index:= precision;
while (index > 0) and
((index >= PiDataModule.start_position) or (carry <> 0)) do
begin
temp:= vn^[index] * Multiplier + carry;
carry:= temp div LessValue;
vn^[index]:= temp mod LessValue;
Dec(index);
end;
end;
procedure TCalculatePi.Divide(Divisor: Integer);
var
index, carry, temp: Integer;
begin
carry:= 0;
for index:= PiDataModule.start_position to precision do
begin
temp:= vn^[index] + (carry * LessValue);
carry:= temp mod Divisor;
vn^[index]:= temp div Divisor;
end;
end;
procedure TCalculatePi.ArcTan(Divisor: Integer);
var
iterations, square, check_zero, index: Integer;
do_add: Boolean;
begin
// Initialise all the local variables
iterations:= 0;
do_add:= True;
square:= Divisor * Divisor;
// Initialise the vn'th array element to 1/Divisor and copy it to the vm'th
// element
SetUp(Divisor);
// Now iterate until we have zeroed the vn array
// Note: That there is always an error in the last few digits due to not
// having enough precision. Hence to get n digits you might like to do
// n+50 or some such
while PiDataModule.start_position < precision do
begin
do_add:= not do_add;
// Note the following divide needs to be done in two steps as the value
// ((2 * iterations) + 3) * square can exceed MaxInt on large runs
Divide(2 * iterations + 3);
Divide(square);
Multiply(2 * iterations + 1);
if do_add then
Add
else
Subtract;
// Calculate the new location of the first zero in the vn array
check_zero:= PiDataModule.start_position;
while (vn^[check_zero + 1] = 0) and (check_zero < precision) do
begin
Inc(PiDataModule.start_position);
Inc(check_zero);
end;
Inc(Iterations);
Application.ProcessMessages;
end;
// And now write the data to a storage file
WriteSource('output' + IntToStr(Divisor) + '.txt', Divisor, iterations);
end;
// Yes, I admit it, I was incredibly lazy here, but it works.
procedure TCalculatePi.WriteSource(FileName: string;
Divisor, Iterations: Integer);
var
index: Integer;
temp: string;
output_file: Text;
begin
assign(output_file, FileName);
try
rewrite(output_file);
if (Divisor = 0) and (Iterations = 0) then
begin
writeln(output_file, 'PI = 3.+');
writeln(output_file);
for index:= 2 to precision do
begin
temp:= IntToStr(vm^[index]);
while Length(temp) < MinPlaces do
temp:= '0' + temp;
write(output_file, temp);
if (index - 1) mod 100 = 0 then
writeln(output_file)
else if (index - 1) mod 10 = 0 then
write(output_file, ' ');
end;
end
else
begin
writeln(output_file, 'Arctan(1/' + IntToStr(Divisor) + ')');
writeln(output_file);
writeln(output_file, 'Iterations = ' + IntToStr(Iterations));
writeln(output_file);
for index:= 1 to precision do
writeln(output_file, IntToStr(vm^[index]));
end;
finally
close(output_file);
end;
end;
procedure TCalculatePi.ReadSource(FileName: string);
var
index: Integer;
input_file: Text;
a_bit: string;
begin
assign(input_file, FileName);
try
reset(input_file);
readln(input_file);
readln(input_file);
readln(input_file);
readln(input_file);
for index:= 1 to precision do
begin
readln(input_file, a_bit);
vn^[index]:= StrToInt(a_bit);
end;
finally
close(input_file);
end;
end;
procedure TCalculatePi.Sum;
var
output_file: Text;
begin
PiDataModule.start_position:= 1;
ReadSource('output18.txt');
Multiply(48);
Move(vn^, vm^, precision);
PiDataModule.start_position:= 1;
ReadSource('output57.txt');
Multiply(32);
Add;
PiDataModule.start_position:= 1;
ReadSource('output239.txt');
Multiply(20);
Subtract;
WriteSource('pi.txt', 0, 0);
end;
end.